/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hadoop.hdfs.server.namenode;

import java.io.IOException;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;

/**
 * Feature for under-construction file.
 * 处于构建状态的特征,构建状态描述的是当客户端为写或者追加写数据打开HDFS文件时,文件所处的状态就是构建状态
 */
@InterfaceAudience.Private
public class FileUnderConstructionFeature implements INode.Feature {
    /**
     * 发起文件写操作的客户端名称,这个属于也用于租约管理
     *
     * 租约是namenode维护的给予客户端在一定期限内可以进行文件写操作的权限的合同
     */
    private String clientName; // lease holder
    // 客户端所在主机
    private final String clientMachine;

    public FileUnderConstructionFeature(final String clientName, final String clientMachine) {
        this.clientName = clientName;
        this.clientMachine = clientMachine;
    }

    public String getClientName() {
        return clientName;
    }

    void setClientName(String clientName) {
        this.clientName = clientName;
    }

    public String getClientMachine() {
        return clientMachine;
    }

    /**
     * Update the length for the last block
     *
     * @param lastBlockLength The length of the last block reported from client
     * @throws IOException 更新文件最后一个正在写的数据块长度
     */
    void updateLengthOfLastBlock(INodeFile f, long lastBlockLength)
            throws IOException {
        BlockInfo lastBlock = f.getLastBlock();
        assert (lastBlock != null) : "The last block for path "
                + f.getFullPathName() + " is null when updating its length";
        assert (lastBlock instanceof BlockInfoUnderConstruction)
                : "The last block for path " + f.getFullPathName()
                + " is not a BlockInfoUnderConstruction when updating its length";
        lastBlock.setNumBytes(lastBlockLength);
    }

    /**
     * When deleting a file in the current fs directory, and the file is contained
     * in a snapshot, we should delete the last block if it's under construction
     * and its size is 0.
     * <p>
     * 删除快照文件中的最后一个长度为0的数据块
     */
    void cleanZeroSizeBlock(final INodeFile f,
                            final BlocksMapUpdateInfo collectedBlocks) {
        final BlockInfo[] blocks = f.getBlocks();
        if (blocks != null && blocks.length > 0
                && blocks[blocks.length - 1] instanceof BlockInfoUnderConstruction) {
            BlockInfoUnderConstruction lastUC =
                    (BlockInfoUnderConstruction) blocks[blocks.length - 1];
            if (lastUC.getNumBytes() == 0) {
                // this is a 0-sized block. do not need check its UC state here
                collectedBlocks.addDeleteBlock(lastUC);
                f.removeLastBlock(lastUC);
            }
        }
    }
}
